'use strict';
const RequestUtil = require('../../util/RequestUtil');
const CommonService = require("../CommonService");
const WxError = require("../../error/WxError");
const {StringUtil} = require('y-node-tool');

/**
 * 小程序认证
 */
class AuthService extends CommonService {


    /**
     * 登录凭证校验<br/>
     * <a>https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html</a>
     * @param jsCode {string} 登录时获取的 code
     * @return {Promise <{openid:string,session_key:string,unionid:string}>}
     * @throws WxError
     */
    static async code2Session(jsCode) {
        const params = {
            appid: this.appid,
            secret: this.secret,
            js_code: jsCode,
            grant_type: 'authorization_code'
        }
        const data = await RequestUtil.get('https://api.weixin.qq.com/sns/jscode2session', params);
        WxError.throwsErr(data.errcode, data.errmsg);


        return {
            openid: data.openid,
            sessionKey: data.session_key,
            unionid: data.unionid
        }

    }

    /**
     * 检查加密信息是否由微信生成（当前只支持手机号加密数据），只能检测最近3天生成的加密数据
     * <a>https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.checkEncryptedData.html</a>
     * @param encryptedMsgHash {string} 加密数据的sha256，通过Hex（Base16）编码后的字符串
     * @return {Promise<{vaild:boolean,createTime:number}>}
     * @throws {WxError}
     */
    static async checkEncryptedData(encryptedMsgHash) {

        const accessToken = this.cacheService.getCacheAccessToken(this.appid);

        let url = 'https://api.weixin.qq.com/wxa/business/checkencryptedmsg';

        const data = {
            accessToken: accessToken,
            encrypted_msg_hash: encryptedMsgHash
        }

        const result = await RequestUtil.post(url, data);
        //throws
        WxError.throwsErr(result, errcode, result.errmsg);

        return {vaild: result.vaild, createTime: result.create_time}
    }

    /**
     * 用户支付完成后，获取该用户的 UnionId，无需用户授权<br/>
     * 注意：调用前需要用户完成支付，且在支付后的五分钟内有效.<br/>
     * 微信支付订单号（transaction_id）和 微信支付商户订单号和微信支付商户号（out_trade_no 及 mch_id） 二选一,
     * <a>https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/user-info/auth.getPaidUnionId.html<a/>
     * @param openid {string} 支付用户唯一标识
     * @param transactionId {string} 微信支付订单号
     * @param mchId {string} 微信支付分配的商户号，和商户订单号配合使用
     * @param outTradeNo {string} 微信支付商户订单号，和商户号配合使用
     * @return {Promise<{unionid:string}>}
     * @throws {WxError}
     *
     */
    static async getPaidUnionId(openid, transactionId, mchId, outTradeNo) {

        if (StringUtil.isBlank(transactionId) && (StringUtil.isEmpty(mchId) || StringUtil.isBlank(outTradeNo))) {
            throw new WxError(-99, '参数错误:要么传入transactionId,要么同时传入mchId和outTradeNo')
        }

        const accessToken = await this.getAccessToken(false);

        let params = {
            access_token: accessToken,
            openid: openid,
        }

        if (StringUtil.isNotBlank(transactionId)) {
            params.transaction_id = transactionId;
        } else {
            params.mch_id = mchId;
            params.out_trade_no = outTradeNo;

        }

        const result = await RequestUtil.get('https://api.weixin.qq.com/wxa/getpaidunionid', params);
        //throws
        WxError.throwsErr(result.errcode, result.errmsg);

        return {unionid: result.unionid}

    }

    /**
     * 获取小程序全局唯一后台接口调用凭据<br/>
     * <a>https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html</a>
     * @param forceRefresh {boolean} 是否强制刷新
     * @return {Promise<{accessToken: string,expiresIn: number}>}
     * @throws WxError
     */
    static async getAccessToken(forceRefresh) {
        //非强制刷新读缓存
        if (!forceRefresh) {
            const accessToken = this.cacheService.getCacheAccessToken(this.appid);
            if (accessToken) {
                return accessToken;
            }
        }

        const params = {
            appid: this.appid,
            secret: this.secret,
            grant_type: 'client_credential'
        }

        const data = await RequestUtil.get('https://api.weixin.qq.com/cgi-bin/token', params);

        //throws

        WxError.throwsErr(data.errcode, data.errmsg);


        this.cacheService.setCacheAccessToken(this.appid, data.access_token, data.expires_in);
        return {
            accessToken: data.access_token,
            expiresIn: data.expires_in
        };

    }
}

module.exports = AuthService;


